package com.powerhua.workflow.logic.jbpm;

import com.powerhua.core.utils.Base64;
import java.util.List;

import org.jbpm.JbpmContext;
import org.jbpm.context.exe.ContextInstance;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.taskmgmt.exe.TaskInstance; 

import com.powerhua.workflow.jbpm.template.JbpmProcess;
import com.powerhua.workflow.jbpm.template.JbpmTemplate;
import com.powerhua.workflow.jbpm.template.impl.JbpmTemplateImpl;
import com.powerhua.workflow.logic.WorkflowManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.file.def.FileDefinition;
import org.jbpm.graph.def.Transition;
import org.jbpm.taskmgmt.exe.SwimlaneInstance;
import org.jbpm.taskmgmt.exe.TaskMgmtInstance; 


public class WorkflowManagerImpl implements WorkflowManager {

    private static final Log log = LogFactory.getLog(WorkflowManagerImpl.class);
    JbpmTemplate jbpmTemplate;

    public WorkflowManagerImpl() {
        jbpmTemplate = new JbpmTemplateImpl();
    }

    @Override
    public String getProcessDefinitions() {
        final StringBuffer result = new StringBuffer("<process-definitions>");
        jbpmTemplate.execute(new JbpmProcess() {

            @SuppressWarnings("unchecked")
            @Override
            public void doInJbpm(JbpmContext jbpmContext) {
                List processDefs = jbpmContext.getGraphSession().findAllProcessDefinitions();

                for (int i = 0; i < processDefs.size(); i++) {
                    ProcessDefinition processDef = (ProcessDefinition) processDefs.get(i);
                    result.append("<process-definition>");
                    result.append("<definition-id>" + processDef.getId() + "</definition-id>");
                    result.append("<definition-name>" + processDef.getName() + "</definition-name>");
                    result.append("<definition-version>" + processDef.getVersion() + "</definition-version>");
                    result.append("</process-definition>");
                }
            }
        });
        result.append("</process-definitions>");
        return result.toString();
    }

    @Override
    public String newProcess(final String userId, final String workflowName,
            final String content, final String comment) {
        final StringBuffer result = new StringBuffer("<new-process-result>");
        jbpmTemplate.execute(new JbpmProcess() {

            @SuppressWarnings("unchecked")
            @Override
            public void doInJbpm(JbpmContext jbpmContext) {
                ProcessInstance procInst = jbpmContext.newProcessInstanceForUpdate(workflowName);

                ContextInstance cxtInst = procInst.getContextInstance();
                if (content != null && !"".equals(content)) {
                    cxtInst.setVariable("formContent", content);
                }
                jbpmContext.save(procInst);

                TaskMgmtInstance taskMgmtInstance = procInst.getTaskMgmtInstance();
                TaskInstance taskInst = taskMgmtInstance.createStartTaskInstance();
                taskInst.start();
                if (comment != null && !"".equals(comment)) {
                    taskInst.addComment(comment);
                }
                result.append("<task-id>" + taskInst.getId() + "</task-id>");
                taskInst.end();
            }
        });
        result.append("</new-process-result>");
        return result.toString();
    }

    @Override
    public String getTasksByUserId(final String userId, final String workflowName, final String state) {
        final StringBuffer result = new StringBuffer("<tasks>");
        jbpmTemplate.execute(new JbpmProcess() {

            @SuppressWarnings("unchecked")
            @Override
            public void doInJbpm(JbpmContext jbpmContext) {
                List<TaskInstance> tasks = jbpmContext.getTaskMgmtSession().findTaskInstances(userId);
                for (int i = 0; i < tasks.size(); i++) {
                    TaskInstance taskInst = (TaskInstance) tasks.get(i);
                    ProcessInstance procInst = taskInst.getProcessInstance();
                    ProcessDefinition procDef = procInst.getProcessDefinition();
                    /*
                     * 如果为ALL，则返回所有的任务
                     */
                    if (!"all".equals(workflowName) && !procDef.getName().equals(workflowName)) {
                        continue;
                    }
                    if ("start".equals(state) && !taskInst.isStartTaskInstance()) {
                        continue;
                    }
                    if ("blocking".equals(state) && !taskInst.isBlocking()) {
                        continue;
                    }
                    if ("open".equals(state) && !taskInst.isOpen()) {
                        continue;
                    }
                    if ("cancelled".equals(state) && !taskInst.isCancelled()) {
                        continue;
                    }
                    if ("signalling".equals(state) && !taskInst.isSignalling()) {
                        continue;
                    }
                    if ("suspended".equals(state) && !taskInst.isSuspended()) {
                        continue;
                    }
                    StringBuffer sb = new StringBuffer("");
                    sb.append("<task>");
                    sb.append("<process-definition>" + procDef.getName() + "</process-definition>");
                    sb.append("<process-instance-id>" + procInst.getId() + "</process-instance-id>");
                    sb.append("<task-instance-id>" + taskInst.getId() + "</task-instance-id>");
                    sb.append("<task-instance>" + taskInst.getName() + "</task-instance>");
                    sb.append("<actor-id>" + taskInst.getActorId() + "</actor-id>");
                    sb.append("<task-start>" + taskInst.isStartTaskInstance() + "</task-start>");
                    sb.append("<task-blocking>" + taskInst.isBlocking() + "</task-blocking>");
                    sb.append("<task-open>" + taskInst.isOpen() + "</task-open>");
                    sb.append("<task-cancelled>" + taskInst.isCancelled() + "</task-cancelled>");
                    sb.append("<task-signalling>" + taskInst.isSignalling() + "</task-signalling>");
                    sb.append("<task-suspended>" + taskInst.isSuspended() + "</task-suspended>");
                    sb.append("</task>");
                    result.append(sb);
                }
            }
        });
        result.append("</tasks>");
        return result.toString();
    }

    @Override
    public String getTaskContentByWorkflowId(final String userId,
            final String taskId, final int isStart) {
        final StringBuffer result = new StringBuffer("<task-content>");
        jbpmTemplate.execute(new JbpmProcess() {

            @Override
            public void doInJbpm(JbpmContext jbpmContext) {
                long taskInstId = Long.parseLong(taskId);
                TaskInstance taskInst = jbpmContext.getTaskInstance(taskInstId);
                SwimlaneInstance swimlaneInst = taskInst.getSwimlaneInstance();
                String actorId = swimlaneInst.getActorId();
                if (!userId.equals(actorId)) {
                    result.append("<error>Actor ID error.</error>");
                    return;
                }
                //
                ProcessInstance procInst = taskInst.getProcessInstance();
                ContextInstance cxtInst = procInst.getContextInstance();
                result.append("<form-content>");
                if (cxtInst.hasVariable("formContent")) {
                    result.append((String) cxtInst.getVariable("formContent"));
                }
                result.append("</form-content>");

                List trans = taskInst.getAvailableTransitions();
                result.append("<transitions>");
                for (int i = 0; i < trans.size(); i++) {
                    Transition tran = (Transition) trans.get(i);
                    String transName = tran.getName();
                    if (transName == null) {
                        transName = "";
                    }
                    result.append("<transition>");
                    result.append(transName);
                    result.append("</transition>");
                }
                result.append("</transitions>");

                if (isStart == 1 && !taskInst.isStartTaskInstance()) {
                    taskInst.start();
                }
            }
        });
        result.append("</task-content>");
        return result.toString();
    }

    @Override
    public String executeTask(final String userId, final String taskId,
            final String nextAction, final String content, final String comment) {
        final StringBuffer result = new StringBuffer("<execute-task-result>");
        jbpmTemplate.execute(new JbpmProcess() {

            @Override
            public void doInJbpm(JbpmContext jbpmContext) {
                long taskInstId = Long.parseLong(taskId);
                TaskInstance taskInst = jbpmContext.getTaskInstance(taskInstId);
                SwimlaneInstance swimlaneInst = taskInst.getSwimlaneInstance();
                String actorId = swimlaneInst.getActorId();
                if (!userId.equals(actorId)) {
                    result.append("<error>Actor ID error.</error>");
                    return;
                }

                ProcessInstance procInst = taskInst.getProcessInstance();
                ContextInstance cxtInst = procInst.getContextInstance();
                if (content != null && !"".equals(content)) {
                    cxtInst.setVariable("formContent", content);
                }
                if (comment != null && !"".equals(comment)) {
                    taskInst.addComment(comment);
                }
                if (nextAction == null || "".equals(nextAction)) {
                    taskInst.end();
                    log.debug("Task instance end without arg.");
                } else {
                    taskInst.end(nextAction);
                    log.debug("Task instance end with arg. arg: " + nextAction);
                }
                jbpmContext.save(taskInst);
                jbpmContext.save(procInst);
                result.append("<info>finished</info>");
            }
        });
        result.append("</execute-task-result>");
        return result.toString();
    }

    @Override
    public String getProcessDefImage(final long processDefId, final long taskId) {
        final StringBuffer result = new StringBuffer("<image>");
        jbpmTemplate.execute(new JbpmProcess() {

            @Override
            public void doInJbpm(JbpmContext jbpmContext) {
                ProcessDefinition procDef = jbpmContext.getGraphSession().getProcessDefinition(processDefId);
                /*
                 * 获取流程图及其位置
                 */
                FileDefinition fileDefinition = procDef.getFileDefinition();
                byte[] gpdBytes = fileDefinition.getBytes("gpd.xml");
                byte[] imageBytes = fileDefinition.getBytes("processimage.jpg");
                result.append(Base64.encode(imageBytes));
            //--------------------------------------------------------------
            }
        });
        result.append("</image>");
        return result.toString();
    }
}
